#!/bin/sh

. "$SPEC_PATH/abstract/metrics"

e2e_test_extra_hash() {
  "$SHELL" "$PROJECT_PATH/stackgres-k8s/ci/build/build-functions.sh" path_hash \
    "$(realpath --relative-to "$PROJECT_PATH" "$SPEC_PATH/abstract/metrics")"
}

e2e_exclusive_lock() {
  true
}

e2e_test_install() {
  if e2e_skip_dbops_secutiry_upgrade
  then
    return
  fi

  PREVIOUS_VERSION_AS_NUMBER="$(get_version_as_number "$STACKGRES_PREVIOUS_VERSION")"
  VERSION_AS_NUMBER_0_9_5="$(get_version_as_number 0.9.5)"
  VERSION_AS_NUMBER_1_2_0_RC1="$(get_version_as_number 1.2.0-RC1)"
  VERSION_AS_NUMBER_1_2_0="$(get_version_as_number 1.2.0)"
  VERSION_AS_NUMBER_1_3_0="$(get_version_as_number 1.3.0)"
  VERSION_AS_NUMBER_1_3_3="$(get_version_as_number 1.3.3)"
  VERSION_AS_NUMBER_1_10_0="$(get_version_as_number 1.10.0-SNAPSHOT)"
  VERSION_AS_NUMBER_1_13_0="$(get_version_as_number 1.13.0-SNAPSHOT)"
  VERSION_AS_NUMBER_1_15_0="$(get_version_as_number 1.15.0-SNAPSHOT)"
  VERSION_AS_NUMBER_1_16_0="$(get_version_as_number 1.16.0-SNAPSHOT)"
  VERSION_AS_NUMBER_1_17_0="$(get_version_as_number 1.17.0-SNAPSHOT)"

  CLUSTER_CRD="sgclusters.stackgres.io"

  EXPECTED_PREVIOUS_OPERATOR_IMAGE="$STACKGRES_PREVIOUS_OPERATOR_IMAGE"
  EXPECTED_PREVIOUS_RESTAPI_IMAGE="$STACKGRES_PREVIOUS_RESTAPI_IMAGE"
  EXPECTED_OPERATOR_IMAGE="$STACKGRES_OPERATOR_IMAGE"
  EXPECTED_RESTAPI_IMAGE="$STACKGRES_RESTAPI_IMAGE"

  RANDOM_VALUE="$(random_string)"
  DISTRIBUTEDLOGS_NAME="$(get_sgdistributedlogs_name distributedlogs)"
  CLUSTER_1_NAME="$(get_sgcluster_name "$CLUSTER_NAME-1")"
  CLUSTER_2_NAME="$(get_sgcluster_name "$CLUSTER_NAME-2")"
  CLUSTER_3_NAME="$(get_sgcluster_name "$CLUSTER_NAME-3")"
  DBOPS_DISTRIBUTEDLOGS_NAME="$(get_sgdbops_name "security-upgrade-logs")"
  DBOPS_1_NAME="$(get_sgdbops_name "security-upgrade-1")"
  DBOPS_2_NAME="$(get_sgdbops_name "security-upgrade-2")"
  DBOPS_3_NAME="$(get_sgdbops_name "security-upgrade-3")"

  PREVIOUS_PATRONI_IMAGE="$(get_component_images "$STACKGRES_PREVIOUS_VERSION")"
  PREVIOUS_PATRONI_IMAGE="$(printf %s "$PREVIOUS_PATRONI_IMAGE" | grep '/patroni\(-ext\)\?:v[0-9.]\+-pg')"
  if [ "$PREVIOUS_VERSION_AS_NUMBER" -ge "$VERSION_AS_NUMBER_1_15_0" ]
  then
    PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE="$(printf '%s' "$PREVIOUS_PATRONI_IMAGE" | tail -n 1)"
  else
    PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE="$(printf '%s' "$PREVIOUS_PATRONI_IMAGE" | grep '/patroni\(-ext\)\?:v[0-9.]\+-pg12\.')"
  fi
  PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE="$(printf '%s' "$PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE" | tail -n 1)"
  PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE_POSTGRES_VERSION_WITH_BUILD_VERSION="${PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE##*-pg}"
  PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE_POSTGRES_VERSION="${PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE_POSTGRES_VERSION_WITH_BUILD_VERSION%%-build-*}"
  PREVIOUS_PATRONI_IMAGE="$(printf '%s' "$PREVIOUS_PATRONI_IMAGE" | grep '/patroni\(-ext\)\?:v[0-9.]\+-pg' | grep -v '.-pg17\.')"
  PREVIOUS_OLDEST_PATRONI_IMAGE="$(printf '%s' "$PREVIOUS_PATRONI_IMAGE" | head -n 1)"
  PREVIOUS_OLDEST_PATRONI_IMAGE_POSTGRES_VERSION_WITH_BUILD_VERSION="${PREVIOUS_OLDEST_PATRONI_IMAGE##*-pg}"
  PREVIOUS_OLDEST_PATRONI_IMAGE_POSTGRES_VERSION="${PREVIOUS_OLDEST_PATRONI_IMAGE_POSTGRES_VERSION_WITH_BUILD_VERSION%%-build-*}"
  PREVIOUS_OLDEST_PATRONI_IMAGE_POSTGRES_MAJOR_VERSION="${PREVIOUS_OLDEST_PATRONI_IMAGE_POSTGRES_VERSION_WITH_BUILD_VERSION%%.*}"
  PREVIOUS_SHARDED_PATRONI_IMAGE="$(printf '%s' "$PREVIOUS_PATRONI_IMAGE" | grep '/patroni\(-ext\)\?:v[0-9.]\+-pg16\.' | head -n 1)"
  PREVIOUS_SHARDED_PATRONI_IMAGE_POSTGRES_VERSION_WITH_BUILD_VERSION="${PREVIOUS_SHARDED_PATRONI_IMAGE##*-pg}"
  PREVIOUS_SHARDED_PATRONI_IMAGE_POSTGRES_VERSION="${PREVIOUS_SHARDED_PATRONI_IMAGE_POSTGRES_VERSION_WITH_BUILD_VERSION%%-build-*}"
  PREVIOUS_SHARDED_PATRONI_IMAGE_POSTGRES_MAJOR_VERSION="${PREVIOUS_SHARDED_PATRONI_IMAGE_POSTGRES_VERSION_WITH_BUILD_VERSION%%.*}"
  PREVIOUS_PATRONI_IMAGE="$(printf '%s' "$PREVIOUS_PATRONI_IMAGE" | tail -n 1)"
  PREVIOUS_PATRONI_IMAGE_POSTGRES_VERSION_WITH_BUILD_VERSION="${PREVIOUS_PATRONI_IMAGE##*-pg}"
  PREVIOUS_PATRONI_IMAGE_POSTGRES_VERSION="${PREVIOUS_PATRONI_IMAGE_POSTGRES_VERSION_WITH_BUILD_VERSION%%-build-*}"
  PREVIOUS_PATRONI_IMAGE_POSTGRES_MAJOR_VERSION="${PREVIOUS_PATRONI_IMAGE_POSTGRES_VERSION_WITH_BUILD_VERSION%%.*}"
  PATRONI_IMAGE="$(get_component_images "$STACKGRES_VERSION")"
  PATRONI_IMAGE="$(printf %s "$PATRONI_IMAGE" | grep '/patroni\(-ext\)\?:v[0-9.]\+-pg')"
  OLDEST_PATRONI_IMAGE="$(printf %s "$PATRONI_IMAGE" | grep '/patroni\(-ext\)\?:v[0-9.]\+-pg'"$PREVIOUS_OLDEST_PATRONI_IMAGE_POSTGRES_VERSION-")"
  OLDEST_PATRONI_IMAGE="$(printf '%s' "$OLDEST_PATRONI_IMAGE" | tail -n 1)"
  SHARDED_PATRONI_IMAGE="$(printf %s "$PATRONI_IMAGE" | grep '/patroni\(-ext\)\?:v[0-9.]\+-pg'"$PREVIOUS_SHARDED_PATRONI_IMAGE_POSTGRES_VERSION-")"
  SHARDED_PATRONI_IMAGE="$(printf '%s' "$SHARDED_PATRONI_IMAGE" | tail -n 1)"
  if [ "$PREVIOUS_VERSION_AS_NUMBER" -ge "$VERSION_AS_NUMBER_1_15_0" ]
  then
    DISTRIBUTEDLOGS_PATRONI_IMAGE="$(printf '%s' "$PATRONI_IMAGE" | grep '/patroni\(-ext\)\?:v[0-9.]\+-pg'"${PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE_POSTGRES_VERSION%.*}"'\.')"
  else
    DISTRIBUTEDLOGS_PATRONI_IMAGE="$(printf %s "$PATRONI_IMAGE" | grep '/patroni\(-ext\)\?:v[0-9.]\+-pg12\.')"
  fi
  DISTRIBUTEDLOGS_PATRONI_IMAGE="$(printf %s "$DISTRIBUTEDLOGS_PATRONI_IMAGE" | grep '/patroni\(-ext\)\?:v[0-9.]\+-pg'"${PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE_POSTGRES_VERSION%.*}\.${PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE_POSTGRES_VERSION#*.}-")"
  DISTRIBUTEDLOGS_PATRONI_IMAGE="$(printf '%s' "$DISTRIBUTEDLOGS_PATRONI_IMAGE" | tail -n 1)"
  PATRONI_IMAGE="$(printf %s "$PATRONI_IMAGE" | grep '/patroni\(-ext\)\?:v[0-9.]\+-pg'"$PREVIOUS_PATRONI_IMAGE_POSTGRES_VERSION-")"
  PATRONI_IMAGE="$(printf '%s' "$PATRONI_IMAGE" | tail -n 1)"

  e2e_cleanup

  e2e_load_images

  if [ "$PREVIOUS_VERSION_AS_NUMBER" -ge "$VERSION_AS_NUMBER_1_16_0" ]
  then
    install_prometheus_operator
  elif [ "$PREVIOUS_VERSION_AS_NUMBER" -gt "$VERSION_AS_NUMBER_1_3_3" ]
  then
    E2E_GRAFANA_VERSION=9.5.21 install_prometheus_operator
  elif [ "$PREVIOUS_VERSION_AS_NUMBER" -gt "$VERSION_AS_NUMBER_0_9_5" ]
  then
    E2E_GRAFANA_VERSION=8.5.13 install_prometheus_operator
  else
    E2E_GRAFANA_VERSION=8.5.13 install_prometheus_operator_for_version 12.8.0
  fi
  e2e_install_previous_operator

  kubectl create namespace "$CLUSTER_NAMESPACE" 2>/dev/null \
    || kubectl get namespace "$CLUSTER_NAMESPACE" >/dev/null

  install_minio

  create_or_replace_cluster_for_version "$STACKGRES_PREVIOUS_VERSION" "$CLUSTER_NAME" "$CLUSTER_NAMESPACE" 1 \
    --set cluster.create=false \
    --set-string cluster.postgres.version="$PREVIOUS_PATRONI_IMAGE_POSTGRES_VERSION" \
    --set instanceProfiles[0].name=size-s \
    --set instanceProfiles[0].cpu=125m \
    --set instanceProfiles[0].memory=512Mi \
    --set-string cluster.configurations.sgPostgresConfig=postgresconf-"${PREVIOUS_PATRONI_IMAGE_POSTGRES_VERSION%.*}" \
    --set configurations.objectstorage.create=true \
    --set-string cluster.configurations.backups.sgObjectStorage=backupconf \
    --set-string cluster.configurations.backups.cronSchedule='0 5 31 2 *' \
    --set cluster.configurations.backups.performance.maxDiskBandwidth=10485760 \
    --set cluster.configurations.backups.performance.maxNetworkBandwidth=5242880 \
    --set-string configurations.postgresconfig.postgresql\\.conf.max_connections=100 \
    --set-string configurations.postgresconfig.postgresql\\.conf.invalid_param=true \
    --set distributedLogs.enabled=true \
    --set distributedLogs.create=true \
    --set-string cluster.distributedLogs.sgDistributedLogs="$DISTRIBUTEDLOGS_NAME" \
    --set-string distributedLogs.persistentVolume.size=128Mi

  create_or_replace_cluster_for_version "$STACKGRES_PREVIOUS_VERSION" \
    "$CLUSTER_1_NAME" "$CLUSTER_NAMESPACE" 1 \
    --set configurations.create=false --set instanceProfiles=false \
    --set-string cluster.sgInstanceProfile=size-s \
    --set-string cluster.configurations.sgPostgresConfig=postgresconf-"${PREVIOUS_PATRONI_IMAGE_POSTGRES_VERSION%.*}" \
    --set-string cluster.postgres.version="$PREVIOUS_PATRONI_IMAGE_POSTGRES_VERSION" \
    --set cluster.configurations.observability.prometheusAutobind=true \
    --set configurations.objectstorage.create=false \
    --set-string cluster.configurations.backups.sgObjectStorage=backupconf \
    --set-string cluster.configurations.backups.cronSchedule='0 5 31 2 *' \
    --set cluster.configurations.backups.performance.maxDiskBandwidth=10485760 \
    --set cluster.configurations.backups.performance.maxNetworkBandwidth=5242880 \
    --set distributedLogs.enabled=true \
    --set distributedLogs.create=false \
    --set-string cluster.distributedLogs.sgDistributedLogs="$CLUSTER_NAMESPACE.$DISTRIBUTEDLOGS_NAME"

  if [ "$E2E_SPEC_SECURITY_UPGRADE_LOW_PROFILE" != true ]
  then
    create_or_replace_cluster_for_version "$STACKGRES_PREVIOUS_VERSION" \
      "$CLUSTER_2_NAME" "$CLUSTER_NAMESPACE" 2 \
      --set configurations.create=true --set instanceProfiles=false \
      --set configurations.postgresconfig.create=true \
      --set configurations.poolingconfig.create=false \
      --set-string cluster.sgInstanceProfile=size-s \
      --set-string cluster.configurations.sgPostgresConfig=postgresconf-"${PREVIOUS_OLDEST_PATRONI_IMAGE_POSTGRES_VERSION%.*}" \
      --set-string cluster.postgres.version="$PREVIOUS_OLDEST_PATRONI_IMAGE_POSTGRES_VERSION" \
      --set cluster.configurations.observability.prometheusAutobind=true \
      --set configurations.objectstorage.create=false \
      --set-string cluster.configurations.backups.sgObjectStorage=backupconf \
      --set-string cluster.configurations.backups.cronSchedule='0 5 31 2 *' \
      --set cluster.configurations.backups.performance.maxDiskBandwidth=10485760 \
      --set cluster.configurations.backups.performance.maxNetworkBandwidth=5242880 \
      --set distributedLogs.enabled=true \
      --set distributedLogs.create=false \
      --set-string cluster.distributedLogs.sgDistributedLogs="$CLUSTER_NAMESPACE.$DISTRIBUTEDLOGS_NAME"
  
    create_or_replace_sharded_cluster_for_version "$STACKGRES_PREVIOUS_VERSION" \
      "$CLUSTER_3_NAME" "$CLUSTER_NAMESPACE" 3 1 \
      --set configurations.create=true --set instanceProfiles=false \
      --set configurations.postgresconfig.create=true \
      --set configurations.poolingconfig.create=false \
      --set-string cluster.sgInstanceProfile=size-s \
      --set-string cluster.configurations.sgPostgresConfig=postgresconf-sharded-"${PREVIOUS_SHARDED_PATRONI_IMAGE_POSTGRES_VERSION%.*}" \
      --set-string shardedCluster.shards.configurations.sgPostgresConfig=postgresconf-sharded-"${PREVIOUS_SHARDED_PATRONI_IMAGE_POSTGRES_VERSION%.*}" \
      --set-string cluster.postgres.version="$PREVIOUS_SHARDED_PATRONI_IMAGE_POSTGRES_VERSION" \
      --set cluster.configurations.observability.prometheusAutobind=true \
      --set configurations.objectstorage.create=false \
      --set-string cluster.configurations.backups.sgObjectStorage=backupconf \
      --set-string cluster.configurations.backups.cronSchedule='0 5 31 2 *' \
      --set cluster.configurations.backups.performance.maxDiskBandwidth=10485760 \
      --set cluster.configurations.backups.performance.maxNetworkBandwidth=5242880 \
      --set distributedLogs.enabled=true \
      --set distributedLogs.create=false \
      --set-string cluster.distributedLogs.sgDistributedLogs="$CLUSTER_NAMESPACE.$DISTRIBUTEDLOGS_NAME"
  fi

  deploy_curl_pod "$CLUSTER_NAMESPACE"

  wait_pods_running "$CLUSTER_NAMESPACE" 1 "$CLUSTER_1_NAME-[0-9]\+"

  BACKUP_NAME="$(get_sgbackup_name "$CLUSTER_NAME-backup-1")"

  cat << EOF | kubectl create -f -
apiVersion: stackgres.io/$(kubectl get crd sgbackups.stackgres.io --template '{{ (index .spec.versions 0).name }}')
kind: SGBackup
metadata:
  namespace: "$CLUSTER_NAMESPACE"
  name: "$BACKUP_NAME"
spec:
  sgCluster: "$CLUSTER_1_NAME"
  managedLifecycle: false
EOF
  
  wait_until e2e_is_backup_phase "Completed"

  remove_cluster "$CLUSTER_1_NAME" "$CLUSTER_NAMESPACE"
  kubectl create secret generic -n "$CLUSTER_NAMESPACE" secret-script \
    --from-literal=script="CREATE DATABASE secret_managed_sql;"
  kubectl create configmap -n "$CLUSTER_NAMESPACE" configmap-script \
    --from-literal=script="CREATE DATABASE configmap_managed_sql;"
  create_or_replace_cluster_for_version "$STACKGRES_PREVIOUS_VERSION" \
    "$CLUSTER_1_NAME" "$CLUSTER_NAMESPACE" 1 \
    --set configurations.create=false --set instanceProfiles=false \
    --set-string cluster.sgInstanceProfile=size-s \
    --set-string cluster.configurations.sgPostgresConfig=postgresconf-"${PREVIOUS_PATRONI_IMAGE_POSTGRES_VERSION%.*}" \
    --set-string cluster.postgres.version="$PREVIOUS_PATRONI_IMAGE_POSTGRES_VERSION" \
    --set cluster.configurations.observability.prometheusAutobind=true \
    --set configurations.objectstorage.create=false \
    --set-string cluster.configurations.backups.sgObjectStorage=backupconf \
    --set-string cluster.configurations.backups.cronSchedule='0 5 31 2 *' \
    --set cluster.configurations.backups.performance.maxDiskBandwidth=10485760 \
    --set cluster.configurations.backups.performance.maxNetworkBandwidth=5242880 \
    --set-string cluster.managedSql.scripts[0].script="CREATE DATABASE managed_sql;" \
    --set-string cluster.managedSql.scripts[1].scriptFrom.secretKeyRef.name=secret-script \
    --set-string cluster.managedSql.scripts[1].scriptFrom.secretKeyRef.key=script \
    --set-string cluster.managedSql.scripts[2].scriptFrom.configMapKeyRef.name=configmap-script \
    --set-string cluster.managedSql.scripts[2].scriptFrom.configMapKeyRef.key=script \
    --set-string cluster.initialData.restore.fromBackup.name="$BACKUP_NAME" \
    --set-string cluster.metadata.labels.clusterPods.pod-label="$RANDOM_VALUE" \
    --set-string cluster.metadata.annotations.clusterPods.pod-annotation="$RANDOM_VALUE" \
    --set-string cluster.metadata.annotations.primaryService.primary-service-label="$RANDOM_VALUE" \
    --set-string cluster.metadata.annotations.replicasService.replicas-service-label="$RANDOM_VALUE" \
    --set distributedLogs.enabled=true \
    --set distributedLogs.create=false \
    --set-string cluster.distributedLogs.sgDistributedLogs="$CLUSTER_NAMESPACE.$DISTRIBUTEDLOGS_NAME"

  deploy_curl_pod "$CLUSTER_NAMESPACE"

  if [ "$E2E_SPEC_SECURITY_UPGRADE_LOW_PROFILE" != true ]
  then
    wait_pods_running "$CLUSTER_NAMESPACE" 9
  else
    wait_pods_running "$CLUSTER_NAMESPACE" 4
  fi

  WAIT_CLUSTER_AUTHENTICATOR_ONLY=true wait_cluster "$CLUSTER_1_NAME" "$CLUSTER_NAMESPACE"
  switch_cluster_to_first "$CLUSTER_1_NAME" "$CLUSTER_NAMESPACE"
  if [ "$E2E_SPEC_SECURITY_UPGRADE_LOW_PROFILE" != true ]
  then
    WAIT_CLUSTER_AUTHENTICATOR_ONLY=true wait_cluster "$CLUSTER_2_NAME" "$CLUSTER_NAMESPACE"
    switch_cluster_to_first "$CLUSTER_2_NAME" "$CLUSTER_NAMESPACE"
    wait_sharded_cluster "$CLUSTER_3_NAME" "$CLUSTER_NAMESPACE"
  switch_sharded_cluster_to_first "$CLUSTER_3_NAME" "$CLUSTER_NAMESPACE"
  fi
  WAIT_CLUSTER_AUTHENTICATOR_ONLY=true wait_cluster "$DISTRIBUTEDLOGS_NAME" "$CLUSTER_NAMESPACE"
  switch_cluster_to_first "$DISTRIBUTEDLOGS_NAME" "$CLUSTER_NAMESPACE"

  generate_mock_data "$DISTRIBUTEDLOGS_NAME"
  generate_mock_data "$CLUSTER_1_NAME"
  if [ "$E2E_SPEC_SECURITY_UPGRADE_LOW_PROFILE" != true ]
  then
    generate_mock_data "$CLUSTER_2_NAME"
    generate_mock_data "$CLUSTER_3_NAME-coord"
  fi

  PREVIOUS_PATRONI_DISTRIBUTEDLOGS_CONFIG_PATH="$LOG_PATH/previous-patroni-logs-config.json"
  kubectl get endpoints -n "$CLUSTER_NAMESPACE" "$DISTRIBUTEDLOGS_NAME-config" \
    --template '{{ .metadata.annotations.config }}' > "$PREVIOUS_PATRONI_DISTRIBUTEDLOGS_CONFIG_PATH"
  PREVIOUS_PATRONI_1_CONFIG_PATH="$LOG_PATH/previous-patroni-1-config.json"
  kubectl get endpoints -n "$CLUSTER_NAMESPACE" "$CLUSTER_1_NAME-config" \
    --template '{{ .metadata.annotations.config }}' > "$PREVIOUS_PATRONI_1_CONFIG_PATH"
  PREVIOUS_PGBOUNCER_1_CONFIG_PATH="$LOG_PATH/previous-pgbouncer-1-config.ini"
  kubectl get configmap -n "$CLUSTER_NAMESPACE" "$CLUSTER_1_NAME-connection-pooling-config" \
    --template '{{ index .data "pgbouncer.ini" }}' > "$PREVIOUS_PGBOUNCER_1_CONFIG_PATH"
  if [ "$E2E_SPEC_SECURITY_UPGRADE_LOW_PROFILE" != true ]
  then
    PREVIOUS_PATRONI_2_CONFIG_PATH="$LOG_PATH/previous-patroni-2-config.json"
    kubectl get endpoints -n "$CLUSTER_NAMESPACE" "$CLUSTER_2_NAME-config" \
      --template '{{ .metadata.annotations.config }}' > "$PREVIOUS_PATRONI_2_CONFIG_PATH"
    PREVIOUS_PGBOUNCER_2_CONFIG_PATH="$LOG_PATH/previous-pgbouncer-2-config.ini"
    kubectl get configmap -n "$CLUSTER_NAMESPACE" "$CLUSTER_2_NAME-connection-pooling-config" \
      --template '{{ index .data "pgbouncer.ini" }}' > "$PREVIOUS_PGBOUNCER_2_CONFIG_PATH"
    PREVIOUS_PATRONI_3_CONFIG_PATH="$LOG_PATH/previous-patroni-3-config.json"
    kubectl get endpoints -n "$CLUSTER_NAMESPACE" "$CLUSTER_3_NAME-0-config" \
      --template '{{ .metadata.annotations.config }}' > "$PREVIOUS_PATRONI_3_CONFIG_PATH"
    PREVIOUS_PGBOUNCER_3_CONFIG_PATH="$LOG_PATH/previous-pgbouncer-3-config.ini"
    kubectl get configmap -n "$CLUSTER_NAMESPACE" "$CLUSTER_3_NAME-coord-connection-pooling-config" \
      --template '{{ index .data "pgbouncer.ini" }}' > "$PREVIOUS_PGBOUNCER_3_CONFIG_PATH"
  fi
}

e2e_skip_dbops_secutiry_upgrade() {
  ! can_install_operator_version "$STACKGRES_PREVIOUS_VERSION"
}

e2e_load_images() {
  if [ "$E2E_FORCE_IMAGE_PULL" = "true" ] \
    && [ "$E2E_UPGRADE_SKIP_IMAGE_PULL" != true ]
  then
    if [ "$E2E_SKIP_LOAD_OPERATOR" != true ]
    then
      load_operator_images_from "$E2E_OPERATOR_REGISTRY" "$E2E_OPERATOR_REGISTRY_PATH" \
        "$STACKGRES_PREVIOUS_VERSION"
    fi

    if [ "$E2E_SKIP_LOAD_COMPONENTS" != true ]
    then
      E2E_INCLUDE_ONLY_POSTGRES_VERSIONS= load_component_images_from "$E2E_COMPONENTS_REGISTRY" "$E2E_COMPONENTS_REGISTRY_PATH" \
        "$STACKGRES_PREVIOUS_VERSION"
    fi

    if [ "$E2E_SKIP_LOAD_EXTENSIONS" != true ]
    then
      load_extensions_images_from "$E2E_EXTENSIONS_REGISTRY" "$E2E_EXTENSIONS_REGISTRY_PATH" \
        "$STACKGRES_PREVIOUS_VERSION"
    fi
  fi
}

e2e_install_previous_operator() {
  install_operator_previous_version \
    --set grafana.autoEmbed=true \
    --set-string grafana.webHost="prometheus-grafana.$(prometheus_namespace)"
  PREVIOUS_RELEASE_NAME="stackgres-operator"
}

e2e_upgrade_operator() {
  upgrade_operator --reset-values \
    --set grafana.autoEmbed=true \
    --set-string grafana.webHost="prometheus-grafana.$(prometheus_namespace)"
}

e2e_is_backup_phase() {
  [ "$(kubectl get sgbackup -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME" -o=jsonpath='{.status.process.status}')" = "$1" ]
}

e2e_cleanup() {
  k8s_unnamespaced_cleanup
  k8s_cleanup_namespace "$OPERATOR_NAMESPACE"
  k8s_async_cleanup
}

e2e_test_uninstall() {
  if e2e_skip_dbops_secutiry_upgrade
  then
    return
  fi

  e2e_cleanup

  kubectl create namespace "$OPERATOR_NAMESPACE"
  install_operator_only
  wait_pods_running "$OPERATOR_NAMESPACE" 2
}

e2e_test() {
  if e2e_skip_dbops_secutiry_upgrade
  then
    echo "Skip dbops-security-upgrade since previous version of operator $STACKGRES_PREVIOUS_VERSION can not be installed"
    return
  fi

  run_test "Check clusters before operator upgrade" check_before_operator_upgrade

  run_test "Check that operator can be upgraded to newer version" check_operator_upgrade

  run_test "Check that previous CRDs be converted to previous versions" check_previous_versions_conversion_webhooks

  run_test "Check that distributedlogs node can start security upgrade after operator upgrade" check_distributedlogs_security_upgrade_start

  run_test "Check that cluster with 1 node can start security upgrade after operator upgrade with reduced impact" check_cluster_1_security_upgrade_start

  if [ "$E2E_SPEC_SECURITY_UPGRADE_LOW_PROFILE" != true ]
  then
    run_test "Check that cluster with 2 node can start security upgrade after operator upgrade with reduced impact" check_cluster_2_security_upgrade_start

    run_test "Check that cluster with 3 node can start security upgrade after operator upgrade with in-place" check_cluster_3_security_upgrade_start
  fi

  run_test "Check that distributedlogs node can complete security upgrade after operator upgrade with reduced impact" check_distributedlogs_security_upgrade

  run_test "Check that cluster with 1 node can complete security upgrade after operator upgrade with reduced impact" check_cluster_1_security_upgrade

  if [ "$E2E_SPEC_SECURITY_UPGRADE_LOW_PROFILE" != true ]
  then
    run_test "Check that cluster with 2 node can complete security upgrade after operator upgrade with reduced impact" check_cluster_2_security_upgrade

    run_test "Check that cluster with 3 node can complete security upgrade after operator upgrade with in-place" check_cluster_3_security_upgrade
  fi

  run_test "Checking that metrics are exported for cluster with 1 node" check_metrics "$CLUSTER_1_NAME"

  if [ "$E2E_SPEC_SECURITY_UPGRADE_LOW_PROFILE" != true ]
  then
    run_test "Checking that metrics are exported for cluster with 2 node" check_metrics "$CLUSTER_2_NAME"

    run_test "Checking that metrics are exported for cluster with 3 node" check_metrics "$CLUSTER_3_NAME-coord"
  fi

  run_test "Check that the conversion webhooks are configured" check_conversion_webhooks_configured

  run_test "Namespace endpoint should return all kubernetes namespaces" check_namespace
}

check_before_operator_upgrade() {
  check_mock_data_samehost "$CLUSTER_1_NAME"
  if [ "$E2E_SPEC_SECURITY_UPGRADE_LOW_PROFILE" != true ]
  then
    check_mock_data "$CLUSTER_2_NAME"
    check_mock_data_samehost "$CLUSTER_3_NAME" coord-0
  fi

  local RESOURCE
  for RESOURCE in $(
    echo "sgcluster/$CLUSTER_1_NAME"
    if [ "$E2E_SPEC_SECURITY_UPGRADE_LOW_PROFILE" != true ]
    then
      echo "sgcluster/$CLUSTER_2_NAME"
      echo "sgcluster/$CLUSTER_3_NAME-coord"
      echo "sgcluster/$CLUSTER_3_NAME-shard0"
      echo "sgcluster/$CLUSTER_3_NAME-shard1"
    fi
    if [ "$PREVIOUS_VERSION_AS_NUMBER" -ge "$VERSION_AS_NUMBER_1_15_0" ]
    then
      echo "sgcluster/$DISTRIBUTEDLOGS_NAME"
    else
      echo "sgdistributedlogs/$DISTRIBUTEDLOGS_NAME"
    fi
    )
  do
    if wait_until eval 'kubectl wait -n "$CLUSTER_NAMESPACE" "$RESOURCE" \
      --for condition=PendingRestart=false --timeout 0'
    then
      success "$RESOURCE is not pending restart after creation"
    else
      fail "$RESOURCE is pending restart after creation"
    fi
  done

  check_backup_performance_using_deprecated_fields_in_previous_versions
}

check_operator_upgrade() {
  local POD_OPERATOR_IMAGE
  POD_OPERATOR_IMAGE="$(kubectl get pod -n "$OPERATOR_NAMESPACE" -l app="$PREVIOUS_RELEASE_NAME" \
    --template '{{ range .items }}{{ if not .metadata.deletionTimestamp }}{{ range .spec.containers }}{{ printf "%s\n" .image }}{{ end }}{{ end }}{{ end }}' \
    | head -n 1)"
  if printf %s "$POD_OPERATOR_IMAGE" | grep -q '/operator:'
  then
    POD_OPERATOR_IMAGE="$(printf %s "$POD_OPERATOR_IMAGE" | grep '/operator:')"
  else
    if [ "$(docker manifest inspect -v "$POD_OPERATOR_IMAGE" | jq -r '.[0].Descriptor.digest')" \
      = "$(docker manifest inspect -v "$EXPECTED_PREVIOUS_OPERATOR_IMAGE" | jq -r '.[0].Descriptor.digest')" ]
    then
      POD_OPERATOR_IMAGE="$EXPECTED_PREVIOUS_OPERATOR_IMAGE"
    fi
  fi
  if ! printf %s "$POD_OPERATOR_IMAGE" | grep -q '^[^/]\+\.[^/]\+/'
  then
    POD_OPERATOR_IMAGE="docker.io/$POD_OPERATOR_IMAGE"
  fi
  if [ "${POD_OPERATOR_IMAGE#*/}" = "${EXPECTED_PREVIOUS_OPERATOR_IMAGE#*/}" ]
  then
    success "Operator pod is using the previous image"
  else
    echo "FAILURE. Operator pod is not using the previous image"
    echo
    echo "Expected previous operator image is $EXPECTED_PREVIOUS_OPERATOR_IMAGE"
    echo
    echo "Used previous operator image is $POD_OPERATOR_IMAGE"
    return 1
  fi
  local POD_RESTAPI_IMAGE
  POD_RESTAPI_IMAGE="$(kubectl get pod -n "$OPERATOR_NAMESPACE" -l "$(
    if [ "$STACKGRES_PREVIOUS_VERSION" = 1.5.0 ]
    then
      printf %s app=stackgres-restapi
    else
      printf %s app=StackGresConfig,stackgres.io/restapi=true
    fi
    )" \
    --template '{{ range .items }}{{ if not .metadata.deletionTimestamp }}{{ range .spec.containers }}{{ printf "%s\n" .image }}{{ end }}{{ end }}{{ end }}' \
    | head -n 1)"
  if printf %s "$POD_RESTAPI_IMAGE" | grep -q '/restapi:'
  then
    POD_RESTAPI_IMAGE="$(printf %s "$POD_RESTAPI_IMAGE" | grep '/restapi:')"
  else
    if [ "$(docker manifest inspect -v "$POD_RESTAPI_IMAGE" | jq -r '.[0].Descriptor.digest')" \
      = "$(docker manifest inspect -v "$EXPECTED_PREVIOUS_RESTAPI_IMAGE" | jq -r '.[0].Descriptor.digest')" ]
    then
      POD_RESTAPI_IMAGE="$EXPECTED_PREVIOUS_RESTAPI_IMAGE"
    fi
  fi
  if ! printf %s "$POD_RESTAPI_IMAGE" | grep -q '^[^/]\+\.[^/]\+/'
  then
    POD_RESTAPI_IMAGE="docker.io/$POD_RESTAPI_IMAGE"
  fi
  if [ "${POD_RESTAPI_IMAGE#*/}" = "${EXPECTED_PREVIOUS_RESTAPI_IMAGE#*/}" ]
  then
    success "Restapi pod is using the previous image"
  else
    echo "FAILURE. Restapi pod is not using the previous image"
    echo
    echo "Expected previous restapi image is $EXPECTED_PREVIOUS_RESTAPI_IMAGE"
    echo
    echo "Used previous restapi image is $POD_RESTAPI_IMAGE"
    return 1
  fi

  e2e_upgrade_operator

  kubectl rollout status -n "$OPERATOR_NAMESPACE" "$(kubectl get deployment -n "$OPERATOR_NAMESPACE" -l app=stackgres-operator -o name)"
  POD_OPERATOR_IMAGE="$(kubectl get pod -n "$OPERATOR_NAMESPACE" -l app=stackgres-operator --sort-by '{.metadata.creationTimestamp}' \
    --template '{{ range .items }}{{ if not .metadata.deletionTimestamp }}{{ range .spec.containers }}{{ printf "%s\n" .image }}{{ end }}{{ end }}{{ end }}' \
    | grep '/operator:' | tail -n 1 | grep .)"
  if ! printf %s "$POD_OPERATOR_IMAGE" | grep -q '^[^/]\+\.[^/]\+/'
  then
    POD_OPERATOR_IMAGE="docker.io/$POD_OPERATOR_IMAGE"
  fi
  if [ "${POD_OPERATOR_IMAGE#*/}" = "${EXPECTED_OPERATOR_IMAGE#*/}" ]
  then
    success "Operator pod is using the new operator image"
  else
    echo "FAILURE. Operator pod is not using the new operator image"
    echo
    echo "Expected new operator image is $EXPECTED_OPERATOR_IMAGE"
    echo
    echo "Used new operator image is $POD_OPERATOR_IMAGE"
    return 1
  fi
  DEPLOYMENT_RESTAPI="$(wait_until eval 'kubectl get deployment -n "$OPERATOR_NAMESPACE" stackgres-restapi -o name | grep .')"
  timeout "$E2E_TIMEOUT" kubectl rollout status -n "$OPERATOR_NAMESPACE" "$DEPLOYMENT_RESTAPI"
  POD_RESTAPI_IMAGE="$(kubectl get pod -n "$OPERATOR_NAMESPACE" -l app=StackGresConfig,stackgres.io/restapi=true --sort-by '{.metadata.creationTimestamp}' \
    --template '{{ range .items }}{{ if not .metadata.deletionTimestamp }}{{ range .spec.containers }}{{ printf "%s\n" .image }}{{ end }}{{ end }}{{ end }}' \
    | grep '/restapi:' | tail -n 1 | grep .)"
  if ! printf %s "$POD_RESTAPI_IMAGE" | grep -q '^[^/]\+\.[^/]\+/'
  then
    POD_RESTAPI_IMAGE="docker.io/$POD_RESTAPI_IMAGE"
  fi
  if [ "${POD_RESTAPI_IMAGE#*/}" = "${EXPECTED_RESTAPI_IMAGE#*/}" ]
  then
    success "Operator pod is using the new restapi image"
  else
    echo "FAILURE. Operator pod is not using the new restapi image"
    echo
    echo "Expected new restapi image is $EXPECTED_RESTAPI_IMAGE"
    echo
    echo "Used new restapi image is $POD_RESTAPI_IMAGE"
    return 1
  fi
}

check_previous_versions_conversion_webhooks() {
  kubectl proxy --port=9090 &
  KUBECTL_PROXY_PID=$!
  trap_kill "$KUBECTL_PROXY_PID"
  ANY_CONVERSION_FAILED=false
  for CRD_NAME in sgclusters sginstanceprofiles \
    sgpgconfigs sgpoolconfigs sgbackupconfigs \
    sgbackups sgdbops sgdistributedlogs
  do
    for PREVIOUS_API_VERSION in $(kubectl get crd "$CRD_NAME.stackgres.io" \
      -o=jsonpath='{ .spec.versions[?(@.storage != true)].name }')
    do
      if curl -f -s -k -X GET  -H "Accept: application/json" \
        "http://localhost:9090/apis/stackgres.io/$PREVIOUS_API_VERSION/$CRD_NAME" > /dev/null
      then
        success "$CRD_NAME.stackgres.io can be converted to $PREVIOUS_API_VERSION"
      else
        fail_no_return "$CRD_NAME.stackgres.io can not be converted to $PREVIOUS_API_VERSION"
        ANY_CONVERSION_FAILED=true
      fi
    done
  done
  kill "$KUBECTL_PROXY_PID"
  if "$ANY_CONVERSION_FAILED"
  then
    return 1
  fi
}

check_distributedlogs_security_upgrade_start() {
  local PREVIOUS_PATRONI_IMAGE="$PREVIOUS_DISTRIBUTEDLOGS_PATRONI_IMAGE"

  check_cluster_security_upgrade_start \
    "$DISTRIBUTEDLOGS_NAME" "$DBOPS_DISTRIBUTEDLOGS_NAME" "InPlace" \
    "$PREVIOUS_PATRONI_DISTRIBUTEDLOGS_CONFIG_PATH" ""
}

check_cluster_1_security_upgrade_start() {
  check_no_unrecognized_property_exception

  check_mutations

  kubectl delete sgbackup -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME"
  check_cluster_security_upgrade_start \
    "$CLUSTER_1_NAME" "$DBOPS_1_NAME" "ReducedImpact" \
    "$PREVIOUS_PATRONI_1_CONFIG_PATH" "$PREVIOUS_PGBOUNCER_1_CONFIG_PATH"
}

check_cluster_2_security_upgrade_start() {
  local PREVIOUS_PATRONI_IMAGE="$PREVIOUS_OLDEST_PATRONI_IMAGE"

  check_cluster_security_upgrade_start \
    "$CLUSTER_2_NAME" "$DBOPS_2_NAME" "ReducedImpact" \
    "$PREVIOUS_PATRONI_2_CONFIG_PATH" "$PREVIOUS_PGBOUNCER_2_CONFIG_PATH"
}

check_cluster_3_security_upgrade_start() {
  local PREVIOUS_PATRONI_IMAGE="$PREVIOUS_SHARDED_PATRONI_IMAGE"

  check_sharded_cluster_security_upgrade_start \
    "$CLUSTER_3_NAME" "$DBOPS_3_NAME" "InPlace" \
    "$PREVIOUS_PATRONI_3_CONFIG_PATH" "$PREVIOUS_PGBOUNCER_3_CONFIG_PATH"
}

check_distributedlogs_security_upgrade() {
  local PATRONI_IMAGE="$DISTRIBUTEDLOGS_PATRONI_IMAGE"

  check_cluster_security_upgrade \
    "$DISTRIBUTEDLOGS_NAME" "$DBOPS_DISTRIBUTEDLOGS_NAME" "InPlace"
}

check_cluster_1_security_upgrade() {
  check_cluster_security_upgrade \
    "$CLUSTER_1_NAME" "$DBOPS_1_NAME" "ReducedImpact"
}

check_cluster_2_security_upgrade() {
  local PATRONI_IMAGE="$OLDEST_PATRONI_IMAGE"

  check_cluster_security_upgrade \
    "$CLUSTER_2_NAME" "$DBOPS_2_NAME" "ReducedImpact"
}

check_cluster_3_security_upgrade() {
  local PATRONI_IMAGE="$SHARDED_PATRONI_IMAGE"

  check_sharded_cluster_security_upgrade \
    "$CLUSTER_3_NAME" "$DBOPS_3_NAME" "InPlace"
}

check_cluster_security_upgrade_start() {
  local CLUSTER_NAME="$1"
  local DBOPS_NAME="$2"
  local METHOD="$3"
  local PREVIOUS_PATRONI_CONFIG_PATH="$4"
  local PREVIOUS_PGBOUNCER_CONFIG_PATH="$5"
  shift 5

  check_cluster_before_security_upgrade

  if [ "$CLUSTER_NAME" = "$DISTRIBUTEDLOGS_NAME" ] \
    && [ "$PREVIOUS_VERSION_AS_NUMBER" -lt "$VERSION_AS_NUMBER_1_15_0" ]
  then
    wait_until run_query -h "$CLUSTER_NAME" -d "test" -q "SELECT 1"
  fi

  check_mock_data_samehost "$CLUSTER_NAME"

  cat << EOF | kubectl create -f -
apiVersion: stackgres.io/v1
kind: SGDbOps
metadata:
  name: $DBOPS_NAME
  namespace: $CLUSTER_NAMESPACE
spec:
  sgCluster: $CLUSTER_NAME
  op: securityUpgrade
  maxRetries: 3
  securityUpgrade:
    method: $METHOD
EOF

  assert_dbops_running "$DBOPS_NAME" "$CLUSTER_NAMESPACE"

  wait_until eval '[ "$(kubectl get sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" -o json \
    | jq --argjson timestamp "$(date +%s)" ".metadata.annotations[\"stackgres.io/lockTimeout\"] | . // \"0\" | tonumber - \$timestamp")" -gt 0 ]'
  if kubectl patch sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" --type json \
    -p '[{"op":"replace","path":"/spec/metadata","value":{"annotations":{"allResources":{"'"$(random_string)"'": "'"$(random_string)"'"}}}}]' \
    >/dev/null 2>&1
  then
    fail "Cluster has been updated while locked."
  else
    success "Cluster has not been updated while locked."
  fi
}

check_sharded_cluster_security_upgrade_start() {
  local SHARDED_CLUSTER_NAME="$1"
  local DBOPS_NAME="$2"
  local METHOD="$3"
  local PREVIOUS_PATRONI_CONFIG_PATH="$4"
  local PREVIOUS_PGBOUNCER_CONFIG_PATH="$5"
  local CLUSTER_NAME
  local CLUSTER_CONFIG_ENDPOINTS_NAME
  shift 5

  local INDEX=0
  for CLUSTER_NAME in "$SHARDED_CLUSTER_NAME-coord" \
    $(seq 0 "$((CLUSTERS - 1))" \
      | while read INDEX
        do
          printf %s "$SHARDED_CLUSTER_NAME-shard$INDEX"
        done)
  do
    CLUSTER_CONFIG_ENDPOINTS_NAME="$SHARDED_CLUSTER_NAME-$INDEX-config" \
      check_cluster_before_security_upgrade
    INDEX="$((INDEX + 1))"
  done

  check_mock_data_samehost "$SHARDED_CLUSTER_NAME" coord-0

  cat << EOF | kubectl create -f -
apiVersion: stackgres.io/v1
kind: SGShardedDbOps
metadata:
  name: $DBOPS_NAME
  namespace: $CLUSTER_NAMESPACE
spec:
  sgShardedCluster: $SHARDED_CLUSTER_NAME
  op: securityUpgrade
  maxRetries: 3
  securityUpgrade:
    method: $METHOD
EOF

  assert_sharded_dbops_running "$DBOPS_NAME" "$CLUSTER_NAMESPACE"

  wait_until eval '[ "$(kubectl get sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" -o json \
    | jq --argjson timestamp "$(date +%s)" ".metadata.annotations[\"stackgres.io/lockTimeout\"] | . // \"0\" | tonumber - \$timestamp")" -gt 0 ]'
  if kubectl patch sgshardedcluster -n "$CLUSTER_NAMESPACE" "$SHARDED_CLUSTER_NAME" --type json \
    -p '[{"op":"replace","path":"/spec/metadata","value":{"annotations":{"allResources":{"'"$(random_string)"'": "'"$(random_string)"'"}}}}]' \
    >/dev/null 2>&1
  then
    fail "Sharded Cluster has been updated while locked."
  else
    success "Sharded Cluster has not been updated while locked."
  fi
}

check_cluster_before_security_upgrade() {
  local CLUSTER_CONFIG_ENDPOINTS_NAME="${CLUSTER_CONFIG_ENDPOINTS_NAME:-$CLUSTER_NAME-config}"

  if wait_until eval 'kubectl wait "$CLUSTER_CRD" -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" \
    --for condition=PendingUpgrade --timeout 0'
  then
    success "Cluster $CLUSTER_NAME is pending upgrade after operator upgrade"
  else
    fail "Cluster $CLUSTER_NAME is not pending upgrade after operator upgrade"
  fi

  if [ -n "$PREVIOUS_PATRONI_IMAGE" ]
  then
    check_sts_is_not_altered "$CLUSTER_NAME"

    local POD
    local PODS
    PODS="$(kubectl get pod -n "$CLUSTER_NAMESPACE" \
      -l "app=StackGresCluster,stackgres.io/cluster-name=$CLUSTER_NAME,stackgres.io/cluster=true" -o name \
      | cut -d / -f 2)"
    for POD in $PODS
    do
      POD_PATRONI_IMAGE="$(kubectl get pod -n "$CLUSTER_NAMESPACE" "$POD" \
        --template '{{ range .spec.containers }}{{ printf "%s\n" .image }}{{ end }}' \
         | grep '/patroni\(-ext\)\?:')"
      if ! printf %s "$POD_PATRONI_IMAGE" | grep -q '^[^/]\+\.[^/]\+/'
      then
        POD_PATRONI_IMAGE="docker.io/$POD_PATRONI_IMAGE"
      fi
      if [ "${POD_PATRONI_IMAGE#*/}" = "${PREVIOUS_PATRONI_IMAGE#*/}" ]
      then
        success "Pod $POD is using the previous patroni image"
      else
        echo "FAILURE. Pod $POD is not using the previous patroni image"
        echo
        echo "Expected previous patroni image is $PREVIOUS_PATRONI_IMAGE"
        echo
        echo "Used previous patroni image is $POD_PATRONI_IMAGE"
        return 1
      fi
    done
  fi

  if [ -n "$PREVIOUS_PATRONI_CONFIG_PATH" ]
  then
    PATRONI_CONFIG="$(kubectl get endpoints -n "$CLUSTER_NAMESPACE" "$CLUSTER_CONFIG_ENDPOINTS_NAME" --template '{{ .metadata.annotations.config }}')"
    PATRONI_CONFIG="$(printf '%s' "$PATRONI_CONFIG" | jq -Sc '. 
      | if .synchronous_mode then . else del(.synchronous_node_count) end
      ')"
    if [ "$PREVIOUS_VERSION_AS_NUMBER" -lt "$VERSION_AS_NUMBER_1_13_0" ]
    then
      PATRONI_CONFIG="$(printf '%s' "$PATRONI_CONFIG" | jq -Sc '. 
        | del(.postgresql.pg_hba)
        ')"
    fi
    if [ "$CLUSTER_NAME" = "$DISTRIBUTEDLOGS_NAME" ] \
      && [ "$PREVIOUS_VERSION_AS_NUMBER" -lt "$VERSION_AS_NUMBER_1_15_0" ]
    then
      PATRONI_CONFIG="$(printf '%s' "$PATRONI_CONFIG" | jq -Sc '. 
        | del(.check_timeline)
        | del(.synchronous_mode)
        | del(.synchronous_mode_strict)
        | del(.postgresql.pg_hba)
        ')"
    fi
    jq -Sc '.
      | if .synchronous_mode then . else del(.synchronous_node_count) end
      | .postgresql.parameters = (.postgresql.parameters
        | if .ssl == null then .ssl = "on" else . end
        | if .ssl_cert_file == null then .ssl_cert_file = "/etc/ssl/tls.crt" else . end
        | if .ssl_key_file == null then .ssl_key_file = "/etc/ssl/tls.key" else . end
        | if .port == null then .port = "5432" else . end
        | if .autovacuum_vacuum_cost_delay == "2" then .autovacuum_vacuum_cost_delay = "2ms" else . end
        | if .checkpoint_timeout == "30" then .checkpoint_timeout = "30s" else . end
        | if .log_autovacuum_min_duration == "0" then .log_autovacuum_min_duration = "0ms" else . end
        | if .log_min_duration_statement == "1000" then .log_min_duration_statement = "1s" else . end
        | if .log_rotation_age == "30" then .log_rotation_age = "30min" else . end
        | if .log_rotation_size == "0" then .log_rotation_size = "0kB" else . end
        | if .log_temp_files == "0" then .log_temp_files = "0kB" else . end
        | if .track_activity_query_size == "4096" then .track_activity_query_size = "4kB" else . end
        | if .restore_command != null then .restore_command = null else . end)
        | .postgresql.recovery_conf = (if .postgresql.recovery_conf == null
          then { restore_command: "exec-with-env '"'backup'"' -- wal-g wal-fetch %f %p" }
          else .postgresql.recovery_conf end)
      | if (.postgresql | has("use_slots"))
        then .
        else .postgresql.use_slots = true end
      ' "$PREVIOUS_PATRONI_CONFIG_PATH" > "$LOG_PATH/previous-patroni-config-filtered.json"
    PREVIOUS_PATRONI_CONFIG="$(cat "$LOG_PATH/previous-patroni-config-filtered.json")"
    if [ "$CLUSTER_NAME" = "$DISTRIBUTEDLOGS_NAME" ]
    then
      PREVIOUS_PATRONI_CONFIG="$(printf '%s' "$PREVIOUS_PATRONI_CONFIG" | jq -Sc '. 
        | del(.postgresql.recovery_conf)
        ')"
    fi
    if [ "$CLUSTER_NAME" = "$DISTRIBUTEDLOGS_NAME" ] \
      && [ "$PREVIOUS_VERSION_AS_NUMBER" -lt "$VERSION_AS_NUMBER_1_17_0" ]
    then
      PREVIOUS_PATRONI_CONFIG="$(printf '%s' "$PREVIOUS_PATRONI_CONFIG" | jq -Sc '. 
        | del(.postgresql.parameters.ssl)
        | del(.postgresql.parameters.ssl_cert_file)
        | del(.postgresql.parameters.ssl_key_file)
        ')"
      PATRONI_CONFIG="$(printf '%s' "$PATRONI_CONFIG" | jq -Sc '. 
        | del(.postgresql.parameters.ssl)
        | del(.postgresql.parameters.ssl_cert_file)
        | del(.postgresql.parameters.ssl_key_file)
        ')"
    fi

    if [ "$PATRONI_CONFIG" = "$PREVIOUS_PATRONI_CONFIG" ]
    then
      success "Cluster $CLUSTER_NAME patroni config did not changed after operator upgrade"
    else
      printf '%s' "$PATRONI_CONFIG" > "$LOG_PATH/patroni-config-actual.json"
      yq -S -y . "$LOG_PATH/patroni-config-actual.json" > "$LOG_PATH/patroni-config-actual.yaml"
      printf '%s' "$PREVIOUS_PATRONI_CONFIG" > "$LOG_PATH/patroni-config-expected.json"
      yq -S -y . "$LOG_PATH/patroni-config-expected.json" > "$LOG_PATH/patroni-config-expected.yaml"
      fail_no_return "Cluster $CLUSTER_NAME patroni config changed after operator upgrade"
      echo
      diff "$LOG_PATH/patroni-config-expected.yaml" "$LOG_PATH/patroni-config-actual.yaml"
      return 1
    fi
  fi

  if [ -n "$PREVIOUS_PGBOUNCER_CONFIG_PATH" ]
  then
    PGBOUNCER_CONFIG="$(kubectl get configmap -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME-connection-pooling-config" --template '{{ index .data "pgbouncer.ini" }}')"
    PGBOUNCER_CONFIG="$(printf '%s' "$PGBOUNCER_CONFIG")"
    cat "$PREVIOUS_PGBOUNCER_CONFIG_PATH" \
      | sed '\#^auth_user = #a client_tls_cert_file = /etc/ssl/tls.crt\nclient_tls_key_file = /etc/ssl/tls.key\nclient_tls_sslmode = prefer' \
      | sed '/server_check_query = ;/d' \
      | sed 's/stats_users = /server_check_query = ;\nstats_users = /' > "$LOG_PATH/previous-pgbouncer-config-filtered.ini"
    PREVIOUS_PGBOUNCER_CONFIG="$(cat "$LOG_PATH/previous-pgbouncer-config-filtered.ini")"

    if [ "$PGBOUNCER_CONFIG" = "$PREVIOUS_PGBOUNCER_CONFIG" ]
    then
      success "Cluster $CLUSTER_NAME pgbouncer config did not changed after operator upgrade"
    else
      printf '%s' "$PGBOUNCER_CONFIG" > "$LOG_PATH/pgbouncer-config-actual.ini"
      printf '%s' "$PREVIOUS_PGBOUNCER_CONFIG" > "$LOG_PATH/pgbouncer-config-expected.ini"
      fail_no_return "Cluster $CLUSTER_NAME pgbouncer config changed after operator upgrade"
      echo
      diff "$LOG_PATH/pgbouncer-config-expected.ini" "$LOG_PATH/pgbouncer-config-actual.ini"
      return 1
    fi
  fi
}

check_cluster_security_upgrade() {
  local CLUSTER_NAME="$1"
  local DBOPS_NAME="$2"
  local METHOD="$3"
  local PRIMARY_INSTANCE
  shift 3

  assert_dbops_completion "$DBOPS_NAME" "$CLUSTER_NAMESPACE" "$((E2E_TIMEOUT * 2))"

  check_cluster_after_security_upgrade

  PRIMARY_INSTANCE="$(kubectl get endpoints -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" \
    --template '{{ .metadata.annotations.leader }}')"
  PRIMARY_INSTANCE="${PRIMARY_INSTANCE#$CLUSTER_NAME-}"

  check_mock_data_samehost "$CLUSTER_NAME" "$PRIMARY_INSTANCE"
}

check_sharded_cluster_security_upgrade() {
  local SHARDED_CLUSTER_NAME="$1"
  local DBOPS_NAME="$2"
  local METHOD="$3"
  local PRIMARY_INSTANCE
  local CLUSTER_NAME
  shift 3

  assert_sharded_dbops_completion "$DBOPS_NAME" "$CLUSTER_NAMESPACE" "$((E2E_TIMEOUT * 2))"

  for CLUSTER_NAME in "$SHARDED_CLUSTER_NAME-coord" \
    "$SHARDED_CLUSTER_NAME-shard0" \
    "$SHARDED_CLUSTER_NAME-shard1"
  do
    check_cluster_after_security_upgrade
  done

  PRIMARY_INSTANCE="$(kubectl get endpoints -n "$CLUSTER_NAMESPACE" "$SHARDED_CLUSTER_NAME-0" \
    --template '{{ .metadata.annotations.leader }}')"
  PRIMARY_INSTANCE="${PRIMARY_INSTANCE#$SHARDED_CLUSTER_NAME-coord-}"

  check_mock_data_samehost "$SHARDED_CLUSTER_NAME" "coord-$PRIMARY_INSTANCE"
}

check_cluster_after_security_upgrade() {
  if wait_until eval 'kubectl wait "$CLUSTER_CRD" -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" \
    --for condition=PendingUpgrade=false --timeout 0'
  then
    success "Cluster $CLUSTER_NAME is not pending upgrade after security upgrade"
  else
    fail "Cluster $CLUSTER_NAME is pending upgrade after security upgrade"
  fi

  local STS_UPDATE_REVISION
  STS_UPDATE_REVISION="$(wait_until kubectl get sts -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME" --template '{{ .status.updateRevision }}')"
  local POD_CONTROLLER_REVISION_HASH
  local POD_CONTROLLER_REVISION_HASHES
  POD_CONTROLLER_REVISION_HASHES="$(kubectl get pod -n "$CLUSTER_NAMESPACE" \
      -l "app=StackGresCluster,stackgres.io/cluster-name=$CLUSTER_NAME,stackgres.io/cluster=true" -o json \
    | jq ".items[]|select(.metadata.name | startswith(\"$CLUSTER_NAME\"))" \
    | jq -r '.metadata.labels."controller-revision-hash"')"

  for POD_CONTROLLER_REVISION_HASH in $POD_CONTROLLER_REVISION_HASHES
  do
    if [ "$POD_CONTROLLER_REVISION_HASH" != "$STS_UPDATE_REVISION" ]
    then
      echo "FAILURE. Cluster $CLUSTER_NAME security upgrade did not updated successfully some pods"
      return 1
    fi
  done

  if [ -n "$PATRONI_IMAGE" ]
  then
    PODS="$(kubectl get pod -n "$CLUSTER_NAMESPACE" \
      -l "app=StackGresCluster,stackgres.io/cluster-name=$CLUSTER_NAME,stackgres.io/cluster=true" -o name \
      | cut -d / -f 2)"
    for POD in $PODS
    do
      POD_PATRONI_IMAGE="$(kubectl get pod -n "$CLUSTER_NAMESPACE" "$POD" \
        --template '{{ range .spec.containers }}{{ printf "%s\n" .image }}{{ end }}' \
         | grep '/patroni\(-ext\)\?:')"
      if [ "$POD_PATRONI_IMAGE" = "$PATRONI_IMAGE" ]
      then
        success "Pod $POD is using the latest patroni image"
      else
        echo "FAILURE. Pod $POD is not using the latest patroni image"
        echo
        echo "Expected new patroni images is '$PATRONI_IMAGE'"
        echo
        echo "Used new patroni image is '$POD_PATRONI_IMAGE'"
        return 1
      fi
    done
  fi

  local PRIMARY_SERVICE_TYPE
  PRIMARY_SERVICE_TYPE="$(kubectl get service -n "$CLUSTER_NAMESPACE" "$CLUSTER_NAME-primary" \
    --template '{{ .spec.type }}')"
  if [ "$PRIMARY_SERVICE_TYPE" = "ExternalName" ]
  then
    success "Cluster $CLUSTER_NAME primary service is of type ExternalName"
  else
    echo "FAILURE. Cluster $CLUSTER_NAME primary service is not of type ExternalName"
    return 1
  fi
}

check_conversion_webhooks_configured(){
  CONVERSTION_STRATEGY="$(kubectl get crd sgclusters.stackgres.io -o jsonpath='{.spec.conversion.strategy}')"

  assert_string_equal "Webhook" "$CONVERSTION_STRATEGY"

  CONVERSTION_STRATEGY="$(kubectl get crd sgdistributedlogs.stackgres.io -o jsonpath='{.spec.conversion.strategy}')"

  assert_string_equal "Webhook" "$CONVERSTION_STRATEGY"
}

check_sts_is_not_altered() {
  local TARGET_CLUSTER="$1"

  local STS_PATRONI_IMAGE
  STS_PATRONI_IMAGE="$(wait_until kubectl get sts -n "$CLUSTER_NAMESPACE" "$TARGET_CLUSTER" -o json \
    | jq -r '.spec.template.spec.containers[] | select(.name == "patroni") | .image')"

  if assert_string_equal "$PREVIOUS_PATRONI_IMAGE" "$STS_PATRONI_IMAGE"
  then
    success "StatefulSet $TARGET_CLUSTER is not being altered on operator upgrade"
  else 
    fail "StatefulSet $TARGET_CLUSTER is being altered on operator upgrade"
  fi
}

check_backup_performance_using_deprecated_fields_in_previous_versions() {
  if [ "$PREVIOUS_VERSION_AS_NUMBER" -ge "$VERSION_AS_NUMBER_1_2_0_RC1" ]
  then
    echo "Previous version used is newer than 1.2.0-RC1, skipping check"
    return
  fi

  if [ "$(kubectl get sgbackup -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME" \
    --template '{{ .status.sgBackupConfig.baseBackups.performance.maxDiskBandwitdh }}')" = '<no value>' ]
  then
    success "The maxDiskBandwitdh has been set to null for sgbackup"
  else
    fail "The maxDiskBandwitdh has not been set to null for sgbackup"
  fi
  if [ "$(kubectl get sgbackup -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME" \
    --template '{{ .status.sgBackupConfig.baseBackups.performance.maxNetworkBandwitdh }}')" = '<no value>' ]
  then
    success "The maxNetworkBandwitdh has been set to null for sgbackup"
  else
    fail "The maxNetworkBandwitdh has not been set to null for sgbackup"
  fi

}

check_no_unrecognized_property_exception() {
  if kubectl logs -n "$CLUSTER_NAMESPACE" \
      -l "app=StackGresCluster,stackgres.io/cluster-name=$CLUSTER_1_NAME,stackgres.io/cluster=true" \
      --all-containers \
    | grep -q 'UnrecognizedPropertyException'
  then
    fail_no_return "The UnrecognizedPropertyException was found in the logs"
    kubectl logs -n "$CLUSTER_NAMESPACE" \
        -l "app=StackGresCluster,stackgres.io/cluster-name=$CLUSTER_1_NAME,stackgres.io/cluster=true" \
        --all-containers \
      | grep 'UnrecognizedPropertyException'
    return 1
  else
    success "The UnrecognizedPropertyException was not found in the logs"
  fi
}

check_mutations() {
  check_backup_performance_mutation

  check_backups_path_mutation

  check_profile_mutation

  check_disable_cluster_resource_requirements_mutation

  check_managed_sql_mutation
}

check_backup_performance_mutation() {
  if [ "$(kubectl get sgbackup -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME" \
    --template '{{ .status.sgBackupConfig.baseBackups.performance.maxDiskBandwitdh }}')" = '<no value>' ]
  then
    success "The maxDiskBandwitdh has been set to null for sgbackup"
  else
    fail "The maxDiskBandwitdh has not been set to null for sgbackup"
  fi
  if [ "$(kubectl get sgbackup -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME" \
    --template '{{ .status.sgBackupConfig.baseBackups.performance.maxNetworkBandwitdh }}')" = '<no value>' ]
  then
    success "The maxNetworkBandwitdh has been set to null for sgbackup"
  else
    fail "The maxNetworkBandwitdh has not been set to null for sgbackup"
  fi
  if [ "$(kubectl get sgbackup -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME" \
    --template '{{ .status.sgBackupConfig.baseBackups.performance.maxDiskBandwidth }}')" = '<no value>' ]
  then
    success "The maxDiskBandwidth has been set to null for sgbackup"
  else
    fail "The maxDiskBandwidth has not been set to null for sgbackup"
  fi
  if [ "$(kubectl get sgbackup -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME" \
    --template '{{ .status.sgBackupConfig.baseBackups.performance.maxNetworkBandwidth }}')" = '<no value>' ]
  then
    success "The maxNetworkBandwidth has been set to null for sgbackup"
  else
    fail "The maxNetworkBandwidth has not been set to null for sgbackup"
  fi
}

check_backups_path_mutation() {
  local PREVIOUS_BACKUP_PATH
  if [ "$PREVIOUS_VERSION_AS_NUMBER" -lt "$VERSION_AS_NUMBER_1_2_0" ]
  then
    PREVIOUS_BACKUP_PATH="$CLUSTER_NAMESPACE/$CLUSTER_1_NAME"
  elif [ "$PREVIOUS_VERSION_AS_NUMBER" -lt "$VERSION_AS_NUMBER_1_10_0" ]
  then
    PREVIOUS_BACKUP_PATH="^sgbackups\.stackgres\.io/$CLUSTER_NAMESPACE/$CLUSTER_1_NAME/$PREVIOUS_PATRONI_IMAGE_POSTGRES_MAJOR_VERSION$"
  else
    PREVIOUS_BACKUP_PATH="^sgbackups\.stackgres\.io/$CLUSTER_NAMESPACE/$CLUSTER_1_NAME/[^/]\+/$PREVIOUS_PATRONI_IMAGE_POSTGRES_MAJOR_VERSION$"
  fi

  if kubectl get sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_1_NAME" -o=jsonpath='{ .spec.configurations.backups[0].path }' \
    | grep -q "$PREVIOUS_BACKUP_PATH"
  then
    success "Backup path was added to cluster backup configuration after operator upgrade"
  else
    fail "Backup path was not added to cluster backup configuration after operator upgrade"
  fi
  if kubectl get sgbackup -n "$CLUSTER_NAMESPACE" "$BACKUP_NAME" --template '{{ .status.backupPath }}' \
    | grep -q "$PREVIOUS_BACKUP_PATH"
  then
    success "Backup path was added to backup status after operator upgrade"
  else
    fail "Backup path was not added to backup status after operator upgrade"
  fi
}

check_profile_mutation() {
  if [ "$(kubectl get sginstanceprofile -n "$CLUSTER_NAMESPACE" "size-s" --template '{{ .spec.containers | len }}')" \
    -gt "0" ]
  then
    success "Containers section was added to instance profiles after operator upgrade"
  else
    fail "Containers section was NOT added to instance profiles after operator upgrade"
  fi
  if [ "$(kubectl get sginstanceprofile -n "$CLUSTER_NAMESPACE" "size-s" --template '{{ .spec.initContainers | len }}')" \
    -gt "0" ]
  then
    success "Init containers section was added to instance profiles after operator upgrade"
  else
    fail "Init containers section was NOT added to instance profiles after operator upgrade"
  fi
}

check_disable_cluster_resource_requirements_mutation() {
  if [ "$(kubectl get sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_1_NAME" -o=jsonpath='{ .spec.nonProductionOptions.disableClusterResourceRequirements }')" \
    = "true" ]
  then
    success "Non production option disableClusterResourceRequirements was set to true in cluster configuration after operator upgrade"
  else
    fail "Non production option disableClusterResourceRequirements was NOT set to true in cluster configuration after operator upgrade"
  fi
}

check_distributedlogs_mutations() {
  if [ "$(kubectl get sgdistributedlogs -n "$CLUSTER_NAMESPACE" "$DISTRIBUTEDLOGS_NAME" -o=jsonpath='{ .spec.sgInstanceProfile }')" \
    != "<no value>" ]
  then
    success "SGInstanceProfile was added to distributed logs configuration after operator upgrade"
  else
    fail "SGInstanceProfile was not added to distributed logs configuration after operator upgrade"
  fi
  if [ "$(kubectl get sgdistributedlogs -n "$CLUSTER_NAMESPACE" "$DISTRIBUTEDLOGS_NAME" -o=jsonpath='{ .spec.configurations.sgPostgresConfig }')" \
    = "<no value>" ]
  then
    success "SGPostgresConfig was added to distributed logs configuration after operator upgrade"
  else
    fail "SGPostgresConfig was not added to distributed logs configuration after operator upgrade"
  fi
  if [ "$(kubectl get sgdistributedlogs -n "$CLUSTER_NAMESPACE" "$DISTRIBUTEDLOGS_NAME" -o=jsonpath='{ .spec.nonProductionOptions.disableClusterResourceRequirements }')" \
    = "true" ]
  then
    success "Non production option disableClusterResourceRequirements was set to true in distributed logs configuration after operator upgrade"
  else
    fail "Non production option disableClusterResourceRequirements was NOT set to true in distributed logs configuration after operator upgrade"
  fi
}

check_managed_sql_mutation() {
  if [ "$(kubectl get sgcluster -n "$CLUSTER_NAMESPACE" "$CLUSTER_1_NAME" --template '{{ len .spec.managedSql.scripts }}')" \
    = "2" ]
  then
    success "Managed SQL was added to cluster configuration after operator upgrade"
  else
    fail "Managed SQL was not added to cluster configuration after operator upgrade"
  fi
  local EXIT_CODE RESULT
  try_function wait_until eval \
    '[ "$(kubectl get sgscript -n "$CLUSTER_NAMESPACE" "$CLUSTER_1_NAME-default" -o name | wc -l)" \
      = "1" ]'
  if "$RESULT"
  then
    success "Default SGScript was created after operator upgrade"
  else
    fail "Default SGScript was not created after operator upgrade"
  fi
  if [ "$PREVIOUS_VERSION_AS_NUMBER" -lt "$VERSION_AS_NUMBER_1_3_0" ]
  then
    if [ "$(kubectl get sgscript -n "$CLUSTER_NAMESPACE" "$CLUSTER_1_NAME-inital-data" -o name | wc -l)" \
      = "1" ]
    then
      success "Initial data SGScript was created after operator upgrade"
    else
      fail "Initial data SGScript was not created after operator upgrade"
    fi
    if [ "$(kubectl get sgscript -n "$CLUSTER_NAMESPACE" "$CLUSTER_1_NAME-inital-data" -o json \
      | jq '.spec.scripts | map(select(.script != null)) | length')" \
      = "1" ]
    then
      success "Initial data SGScript was created with expected number of inline scripts after operator upgrade"
    else
      fail "Initial data SGScript was not created with expected number of inline scripts after operator upgrade"
    fi
    if [ "$(kubectl get sgscript -n "$CLUSTER_NAMESPACE" "$CLUSTER_1_NAME-inital-data" -o json \
      | jq '.spec.scripts | map(select(.scriptFrom != null and .scriptFrom.secretKeyRef)) | length')" \
      = "1" ]
    then
      success "Initial data SGScript was created with expected number of secret scripts after operator upgrade"
    else
      fail "Initial data SGScript was not created with expected number of secret scripts after operator upgrade"
    fi
    if [ "$(kubectl get sgscript -n "$CLUSTER_NAMESPACE" "$CLUSTER_1_NAME-inital-data" -o json \
      | jq '.spec.scripts | map(select(.scriptFrom != null and .scriptFrom.configMapKeyRef)) | length')" \
      = "1" ]
    then
      success "Initial data SGScript was created with expected number of configmap scripts after operator upgrade"
    else
      fail "Initial data SGScript was not created with expected number of configmap scripts after operator upgrade"
    fi
  fi
}

check_namespace() {
  if wait_until check_returned_namespaces
  then
    success "Namespace endpoint returned all namespaces"
    return 0
  else
    fail_no_return "Namespace endpoint not return all namespaces"
    local RETURN EXIT_CODE
    try_function check_returned_namespaces
    return 1
  fi
}

check_returned_namespaces() {
  local NAMESPACES_IN_RESPONSE
  local NAMESPACES_IN_K8S

  NAMESPACES_IN_RESPONSE="$(run_curl -r "stackgres/namespaces" -n "$CLUSTER_NAMESPACE" \
    | jq -r -M -S 'sort_by(.)[]' )"

  NAMESPACES_IN_K8S="$(
    [ "x$E2E_ALLOWED_NAMESPACES" != x ] \
      && printf '%s %s' "$E2E_ALLOWED_NAMESPACES $OPERATOR_NAMESPACE" | tr ' ' '\n' | sort | uniq \
      || kubectl get ns -o json \
    | jq -r -M -S '.items[].metadata.name')"

  [ "$NAMESPACES_IN_RESPONSE" = "$NAMESPACES_IN_K8S" ]
}

